#/*************************************************************************
#    > File Name: Param_MG_Operation.py
#    > Author: Yan Wang
#    > Mail: wangyan@imnu.edu.cn
#    > Created Time: 2022年10月27日 星期四 14时47分14秒
# ************************************************************************/
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Load_Lib import *
from Class_Process import *

class Param_MG(object):
    MG_Dir={}
    MG_Dir_cut={}
    MG_Dir_nocut={}
    MG_Setting = {}
    MG_Results = {}

    _param_dir = {}
    _process   = {}
    _node      = {}
    cut_xection= []

    def __init__(self, process, param_dir):
        self._param_dir = param_dir.Dir()
        self._node      = param_dir.Node()
        self._process   = process.Var()
        self.Set_Param(self._process, self._param_dir)

    def Dir(self):
        return(self.MG_Dir)

    def Setting(self):
        return(self.MG_Dir)

    # 设置MG参数
    def Set_Param(self, process, param_dir):
        print("************** 设置MG 替换参数****************")
        self.Set_Replace_Param(process, param_dir)
        print("************** 设置MG 扫描参数****************")
        self.Set_Scan_Param(process, param_dir)
        print("************** 设置MG 事例文件夹**************")
        self.Set_Event_Folder(process, param_dir)


    def Print(self):
        print("\n MG Param Content is : ")
        self.Replaced_Print()
        self.Scan_Print()
        self.Event_Folder_Print()
        self.Plot_Print()
        self.Multi_Event_Print()
        print("_"*50)


#######################################################################################
######################################      参数设置      #############################
#######################################################################################


# 生成 MG 中的 Param 文件
    def Set_Replace_Param(self, process, param_dir):
        replace_dir = str(param_dir["data"]/("input_"+process["name"]+"/card/"))
        replace_file = "replace_"+process["mode"]+"_param_card"
        sys.path.append(replace_dir)
        replace_command = import_module (replace_file)
        MGparam_label_value, MGparam_replace_value, MGparam_label_width, MGparam_replace_width = replace_command.Read_Replace_Param()
        self.MG_Setting["replace_value"]=MGparam_replace_value
        self.MG_Setting["label_value"]=MGparam_label_value
        self.MG_Setting["label_width"]=MGparam_label_width
        self.MG_Setting["replace_width"]=MGparam_replace_width
        self.MG_Dir["param_out_file"]=param_dir["output_folder"] / "param/{fname}_for_MG.dat".format(fname=process["event_kind"])

        return

    def Replaced_Print(self):
        print("	The replaced param is : ")
        print("		Replaced value :    ", self.MG_Setting["replace_value"])
        print("		Replaced width :    ", self.MG_Setting["replace_width"])
        print("		label value :       ", self.MG_Setting["label_value"])
        print("		label width :       ", self.MG_Setting["label_width"])
        print("		param output file:  ", self.MG_Dir["param_out_file"])


    def Set_Scan_Param(self, process, param_dir):
        scan_param = "scan_param_{}".format(self._process["kind"])
        scan_xection = "scan_xection_{}".format(self._process["kind"])
        self.MG_Dir["param_general_file_name"]=param_dir["output_folder"] / (scan_param+"/param_card_{}.dat")
        self.MG_Dir["xection_general_file_name"]=param_dir["output_folder"] / (scan_xection+"/param_card_{}.dat")
        self.MG_Setting["scan_output_general_name"]="scan_run_[01-{fnum}]_mycode.txt"

    def Scan_Print(self):
        print("	Scan Param is : ")
        print("		param_general_file_name : ", self.MG_Dir["param_general_file_name"])
        print("		scan_output_general_name : ", self.MG_Setting["scan_output_general_name"])


    def Set_Event_Folder(self, process, param_dir):
        # 设置MG工作路径
        print("**********创建带有末态cut的文件夹**********")
        self.MG_Dir["parallel_record_file"]=param_dir["output_folder"] / "parallel_tmp/mg_results_{fname}/".format(fname=process["process_event_kind"])

        self.MG_Dir["original_folder"]=param_dir["MG"] / "{fprocess}".format(fprocess=process["name"])
        event_folder="Events_{fname}".format(fname=process["event_kind"])
        self.MG_Dir["event_stored_folder"]=param_dir["MG"] / event_folder
        self.MG_Dir["combined_event_folder"]=self.MG_Dir["event_stored_folder"] / "{fprocess}_0/Events/".format(fprocess=process["name"])
        MG_split_event_folder=[]
        for num in range(process["folder_num"]):
            new_folder=self.MG_Dir["event_stored_folder"] / "{fprocess}_{fn}/".format(fprocess=process["name"],fn=num+1)
            MG_split_event_folder.append(new_folder)
        self.MG_Dir["split_event_folder"]=MG_split_event_folder

        self.MG_Dir["combined_scan_file"]=self.MG_Dir["combined_event_folder"] / self.MG_Setting["scan_output_general_name"]
        self.MG_Dir["cut_file_name"]=str(self.MG_Dir["combined_scan_file"]).format(fnum=process["BP_length"])
        self.MG_Dir["split_scan_file"]=[this_file / self.MG_Setting["scan_output_general_name"] for this_file in MG_split_event_folder]
        self.MG_Dir["multi_event_files"]=self.MG_Dir["combined_scan_file"]

        if self._process["special_BP"]:
            self.MG_Dir["split_event_folder"]=np.array(self.MG_Dir["split_event_folder"])[np.array(self._process["special_BP"])-1]
            self.MG_Dir["split_scan_file"]=np.array(self.MG_Dir["split_scan_file"])[np.array(self._process["special_BP"])-1]

        # 设置两个私有变量， 用于根据想要的结果，切换MG_Dir的值
        self.MG_Dir_cut = self.MG_Dir.copy()
        self.MG_Dir_nocut = self.MG_Dir.copy()

# 对于考虑 no cut 的事例
        print("**********创建末态no cut的文件夹**********")
        self.MG_Dir_nocut["original_folder"]=param_dir["MG"] / "{fprocess}_nocut/Events/".format(fprocess=process["name"])
        event_folder_nocut="Events_{fname}".format(fname=process["kind"])
        self.MG_Dir_nocut["event_stored_folder"]=param_dir["MG"] / event_folder_nocut
        self.MG_Dir_nocut["combined_event_folder"]=self.MG_Dir_nocut["event_stored_folder"] / "{fprocess}_0/Events/".format(fprocess=process["name"])
        MG_split_event_folder_nocut=[]
        for num in range(process["folder_num"]):
            new_folder=self.MG_Dir_nocut["event_stored_folder"] / "{fprocess}_nocut_{fn}/".format(fprocess=process["name"],fn=num+1)
            MG_split_event_folder_nocut.append(new_folder)
        self.MG_Dir_nocut["split_event_folder"]=MG_split_event_folder_nocut
        self.MG_Dir_nocut["combined_scan_file"]=self.MG_Dir_nocut["combined_event_folder"] / self.MG_Setting["scan_output_general_name"]
        self.MG_Dir_nocut["cut_file_name"]=str(self.MG_Dir_nocut["combined_scan_file"]).format(fnum=process["BP_length"])
        self.MG_Dir_nocut["split_scan_file"]=[this_file / self.MG_Setting["scan_output_general_name"] for this_file in MG_split_event_folder_nocut]

        if self._process["special_BP"]:
            self.MG_Dir_nocut["split_event_folder"]=np.array(self.MG_Dir_nocut["split_event_folder"])[np.array(self._process["special_BP"])-1]
            self.MG_Dir_nocut["split_scan_file"]=np.array(self.MG_Dir_nocut["split_scan_file"])[np.array(self._process["special_BP"])-1]

# 设置parton level截面与其他输入参数作为hotmap的参数。 
        self.MG_Setting["hotmap_variable_name"]="Parton_xection"
        self.MG_Dir["hotmap_dat_file"]=param_dir["output_folder"] / "hotmap_data/{fname}_for_MG_xection.dat".format(fname=process["event_kind"])
        self.MG_Dir["hotmap_C_file"]=param_dir["output_folder"] / "hotmap_code/{fname}_for_MG_xection.C".format(fname=process["event_kind"])


        self.MG_Setting["plot"]={"dat_file": self.MG_Dir["hotmap_dat_file"],
                "C_file": self.MG_Dir["hotmap_C_file"],
                "bins": process["plot"]["bins"],
                "data_length": process["BP_length"],
                "var_name": self.MG_Setting["hotmap_variable_name"],
                "X_name": process["plot"]["X_name"],
                "Y_name": process["plot"]["Y_name"],
                }
        for key, folder in self.MG_Dir.items():
            if key == "split_event_folder" or key == "split_scan_file":
                continue
            if key == "split_event_folder_nocut" or key == "split_scan_file_nocut":
                continue
            Create_Folder(folder,"/")
        for key, folder in self.MG_Dir_nocut.items():
            if key == "split_event_folder" or key == "split_scan_file":
                continue
            if key == "split_event_folder_nocut" or key == "split_scan_file_nocut":
                continue
            Create_Folder(folder,"/")
        return



    def Event_Folder_Print(self):
        print("	The Event with cut Information is : ")
        print("		parallel info record : ", self.MG_Dir["parallel_record_file"])

        print("		original MG folder :", self.MG_Dir["original_folder"])
        print("		event stored folder :", self.MG_Dir["event_stored_folder"])
        print("		combinded BP event folder:", self.MG_Dir["combined_event_folder"])
        print("		combined scan file summery:", self.MG_Dir["combined_scan_file"])
        print("		split BP event folder:", *self.MG_Dir["split_event_folder"], sep="\n			")
        print("		split BP file:", *self.MG_Dir["split_scan_file"], sep="\n			")
        print("	The Event w.o. cut Information is : ")
        print("		original MG folder nocut : ", self.MG_Dir_nocut["original_folder_nocut"])
        print("		event stored folder nocut :", self.MG_Dir_nocut["event_stored_folder_nocut"])
        print("		combinded BP event folder nocut : ", self.MG_Dir_nocut["combined_event_folder_nocut"])
        print("		combined scan file summery : ", self.MG_Dir_nocut["combined_scan_file_nocut"])
        print("		split BP event folder:", *self.MG_Dir_nocut["split_event_folder_nocut"], sep="\n			")
        print("		split BP file:", *self.MG_Dir_nocut["split_scan_file_nocut"], sep="\n			")





    def Plot_Print(self):
        plot=self.MG_Setting["plot"]
        print("	The plot Param is : ")
        print("		dat_file_name: ", plot["dat_file"])
        print("		C_file_name: ", plot["C_file"])
        print("		xname  : ", plot["X_name"])
        print("		yname  : ", plot["Y_name"])
        print("		bins    : ", plot["bins"])
        print("		data_length : ", plot["data_length"])
        print("		var_name: ", plot["var_name"])

        print("	The plot Dir is : ")
        print("		hotmap dat file : ", self.MG_Dir["hotmap_dat_file"])
        print("		hotmap C file: ", self.MG_Dir["hotmap_C_file"])
        print("		hotmap variable name: ", self.MG_Setting["hotmap_variable_name"])

#######################################################################################
######################################       生成事例     #############################
#######################################################################################

# 生成多个MG参数文件。 每个参数生成一个对应的文件
    def Generate_MG_ParamCard_from_DF(self, input_para_df):
        print("根据参数点，生成param_card，参数点为：",input_para_df)
        #需要labels 中包含的需要替换的参数与replaced_value中一致。
        label_count=0
        for keys in self.MG_Setting["label_value"]:
            label_count += self.MG_Setting["label_value"][keys]

        if len(self.MG_Setting["replace_value"]) is not label_count:
            print("Error in Generate_MG_ParamCard_from_DF:  input_dict length is in-consistent with labels line numbers")
            return(None)
# 复制para_card.dat 为多个文件，文件数与data_grid_mh_mHc.tsv中的行数一致。
        replaced_key=Get_Maplist_Key(self.MG_Setting["replace_value"])   #查找replaced_value中的key
        if not self._process["special_BP"]:
            list_number=np.arange(len(self._process["BP_df"]))
        else:
            list_number = self._process["special_BP"]
        file_name_list=Copy_Multi_File(list_number,self._process["param_card"],self.MG_Dir["param_general_file_name"])    #复制source中的文件添加到output_general_file中，并且文件以 special_BP 中的数字依次命名
        print("替换关键词为： ", replaced_key, self.MG_Setting["replace_value"])
        param_list_all = Mapping_DF_to_Sentence(input_para_df,replaced_key,self.MG_Setting["replace_value"])    #replaced_key替换到input_para_df，input替换的列由replaced_content提供
        print("替换后的数据为：", param_list_all)
# 查找需要替换的行的位置
        Replace_Multi_File(self.MG_Setting["label_value"],file_name_list,self._process["param_card"],param_list_all)   #对param_list_all(file_name_list中的)进行labels替换(替换的是source文件)
        print("替换完成， 替换的文件为：",file_name_list)
        return(file_name_list)



# 自动生成几份scan参数文件
# 与 Generate_MG_Param_Card_from_DF 相似， 但是输入变量不同， 可以每一个文件中包含多组参数， 因而用于扫描参数
    def Generate_MG_Scan_ParamCard_from_Dict(self, input_dict):
        #需要input_dict中包含的需要替换的参数与replaced_content 以及 labels中一致。
        if len(input_dict) is not len(self.MG_Setting["replace_value"]):
            print("Error in Generate_MG_Scan_ParamCard_from_Dict:  input_dict length is in-consistent with replaced_content")
            return(None)
        label_count=0
        for keys in self.MG_Setting["label_value"]:
            label_count += self.MG_Setting["label_value"][keys]

        if len(input_dict) is not label_count:
            print("Error in Generate_MG_Scan_ParamCard_from_Dict:  input_dict length is in-consistent with labels line numbers")
            return(None)
    #设置基本替换文件
    # 定义变量
    # 将key单独提取为列表
        if not self._process["special_BP"]:
            list_number=np.arange(len(self._process["BP_df"]))
        else:
            list_number = self._process["special_BP"]
        replaced_key=Get_Maplist_Key(self.MG_Setting["replace_value"])   #提取replaced_value中的key
        file_name_list=Copy_Multi_File(list_number,self._process["param_card"],self.MG_Dir["param_general_file_name"])  #复制source基文件到output_general_file并以target_num依次命名
        param_list_all = Mapping_DictList_to_Sentence(input_dict,replaced_key,self.MG_Setting["replace_value"],self._process["special_BP"])   #替换文件并且依次命名
    # 查找需要替换的行的位置
        Replace_Multi_File(self.MG_Setting["label_value"],file_name_list,self._process["param_card"],param_list_all)   #对param_list_all(file_name_list中的)进行labels替换(替换的是source文件)
        return(file_name_list)



# 复制 MG 的文件夹，并生成事例
#def Generate_MG_Scan_Events(original_folder,split_event_folder, param_replace_value,param_label_value, param_df, node_num, node_name, param_length, param_source, param_general_file_name, run_card, delphes_card):
# 根据需要分解的node_num 将MG中的模拟文件夹拷贝 node_num份，
#判断是否存在文件
    def Generate_MG_Events(self):
        original_folder = self.MG_Dir["original_folder"]
        split_folder = self.MG_Dir["split_event_folder"]
        if not os.path.exists(original_folder):
            print("Error: In MG step: there is no MG original folder")

        print("原始的MG文件夹为: ", original_folder)
        print("根据扫描参数，需要生成的文件夹为 ", split_folder)
        for file_name in split_folder:
            if not os.path.exists(file_name):
                print("此文件夹不存在，拷贝一份：", file_name)
                #将para复制到file_name
                Copy_File(original_folder,file_name)
            else:
                print("文件夹已存在：",file_name, type(file_name))
                event_folder=file_name / "Events"
                print(event_folder)
                if not os.path.exists(event_folder):
                    print("但事例文件夹不存在，创建一个新的事例文件夹：",event_folder, type(event_folder))
                    Create_Folder(event_folder,"/")   #创建文件夹
        print("已经将原始文件夹拷贝到各自扫描点对应的新文件夹:")


        # 生成MG中param的scan文件, 并拷贝至 split_event_folder 定义的文件夹的 Cards/ 中
        print("根据扫描参数点，生成param_card文件，当前输入的数据类型为",self._process["data_style"])
        if self._process["data_style"] == "list":
            input_value_list=Get_Maplist_Key(self.MG_Setting["replace_value"])   #查找key
            input_dict=Make_DictList_from_DF(self._process["BP_df"], self._node["node_num"], input_value_list, self._process["BP_length"])   #分组替换，依次命名
            param_file_list=self.Generate_MG_Scan_ParamCard_from_Dict(input_dict)    #分组替换，依次命名
        elif self._process["data_style"] == "df" : 
            param_file_list=self.Generate_MG_ParamCard_from_DF(self._process["BP_df"])
        else:
            print("In Generate_MG_Events, wrong self._process[\"data_style\"], please a correct value (df/list). The current value is ", self._process["data_style"])
            return
        print("The param files are stored in ", param_file_list)


        # 根据需要将标准参数文件，复制到需要计算的文件夹中
        #if not self._process["MG_lhe_event_exist"]:
        print("Copy param files into MG event folders.")
        for num in range(self._process["folder_num"]):
            Copy_File(param_file_list[num],split_folder[num]/"Cards/param_card.dat")
            Copy_File(self._process["run_card"],    split_folder[num]/"Cards/run_card.dat")
            Copy_File(self._process["delphes_card"],split_folder[num]/"Cards/delphes_card.dat")

        # 进入各个节点运行 MG
        # 首先将进入每个节点后需要执行的命令，写到 MG_command 列表中， MG_command 的长度与 节点数相同， 也与MG中新拷贝的文件夹数目相同
        if self._process["running_method"] == "ssh" and self._process["mode"] == "scan":
            command=[]
            for index_f, file_name in enumerate(split_folder):
                # 定义 ssh_para， 它将会传递到每一个计算节点中执行
                ssh_para={}
                ssh_para["node_name"]=self._node["node_name"][index_f]
                ssh_para["command"]="source ~/.zshrc ; {fdir}/bin/generate_events -f".format(fdir=file_name)
                command.append(ssh_para)
            print("Setting mg running command: ", ssh_para)
        # 进入各个节点运行 MG
            print("Begin Parallel running for each mg folder.")
            #Parallel_Running(Run_Command_with_SSH,command,para["record_file"])
            Parallel_Running(Run_Command_with_SSH,command)
        elif self._process["running_method"] == "ssh" and self._process["mode"] == "seperate": 
            if self._process["folder_num"]%self._node["node_num"] == 0:
                batch_num=self._process["folder_num"]//self._node["node_num"]
            else:
                batch_num=self._process["folder_num"]//self._node["node_num"]+1

            folder_batch = Split_List_n_List(split_folder, batch_num)
            print("The folder_batch are ", folder_batch)
            for folder_list in folder_batch:
                command=[]
                for index_f, file_name in enumerate(folder_list):
                    ssh_para={}
                    ssh_para["node_name"]=self._node["node_name"][index_f]
                    ssh_para["command"]="source ~/.zshrc ; {fdir}/bin/generate_events -f".format(fdir=file_name)
                    command.append(ssh_para)
                print("Setting mg running command: ", ssh_para)
                # 进入各个节点运行 MG
                print("Begin Parallel running for each mg folder.")
                    #Parallel_Running(Run_Command_with_SSH,command,para["record_file"])
                Parallel_Running(Run_Command_with_SSH,command)
        elif self._process["running_method"] == "local" and (self._process["mode"] == "seperate" or self._process["mode"] == "fixed_width"): 
            print("*************in local PC, run seperate parallel *************")
            print("Setting mg running command: ", split_folder)
            print("Begin Parallel running for each mg folder.")
                    #Parallel_Running(Run_Command_with_SSH,command,para["record_file"])
            Parallel_Running(self.Run_MG_single,split_folder)
        elif self._process["running_method"] == "slurm": 
            param={}
            param["command"]="sbatch {}/run_slurm.pbs"
            param["folder"]=split_folder
            Slurm_Running(param)
        elif self._process["running_method"] == "pbs": 
            param={}
            param["command"]="qsub {}/run_pbs.pbs"
            param["folder"]=split_folder
            PBS_Running(param)
        else:
            print("In Generate_MG_Events, wrong self._process[\"running_method\"], please a correct value. The current value is ", self._process["running_method"])


        return()






#通过多核并行处理，执行ARCH命令，针对所有BP，计算结果
    def Run_MG_single(self, file_name):
        MG_bin = os.path.join(str(file_name), 'bin/generate_events')
        print("MG_bin",MG_bin)
        result = subprocess.run([MG_bin, "-f"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return(result)


    def Run(self):
        file_general_name = "path_{}.dat"
        file_name_list=Generate_General_NameList(file_general_name,self.ARCH_Control["dir"]["target"],self._process["BP_length"])
        Create_Folder(self.ARCH_Dir["parallel_output_folder"],"/")
        Parallel_Running(self.run_subprocess, file_name_list, str(self.ARCH_Dir["parallel_output_folder"]))

#######################################################################################
###################################### 如果文件已经生成好 整理文件事例#################
#######################################################################################
#覆盖重复文件
    def Cover_Duplicated_File(self, pattern,folder):
       bk_folder=os.path.join(folder,"bk")   #路径拼接
       Create_Folder(bk_folder,"/")   #创建文件夹
       for key in pattern:
           #print("key",key)
           #print("folder",folder)
           files=Find_File(folder, key)   #查找folder下的key行
           #print("files",files)
           sorted_files=Sort_Files_by_Time(files)
           #print("sourted_files",sorted_files)
           if sorted_files:
               return
           for count,file in enumerate(sorted_files):
               if(count!=len(sorted_files)-1):
                   Move_File(file,bk_folder)
    
    
    
    
     #整理 MG 生成的 Events 文件夹中的 run 文件夹
    def Tidy_MG_Run_Folder(self, folder_name,num):
       mg_file_category=["banner","shower","delphes_events","delphes\.log","djrs","pts","pythia8\.cmd","pythia8_events","pythia8\.log","unweighted_events"]
       #去除要移动的文件夹中，由于生成错误，造成的多余的重复文件，只留下最新的文件
       self.Cover_Duplicated_File(mg_file_category,folder_name)
       #现在同类文件只剩一个，对run文件，更改其序号与新文件夹的序号相同。
       files=Find_File(folder_name,"banner")
       renamed_file_path=os.path.join(folder_name,files[0])
       #将 run_03_tag_1_banner.dat 中的03改名为 新文件夹对应的数字
       Rename_Series_Files(num,renamed_file_path)
       #将 tag 序号，均改为 tag_1
       Multi_Rename_Series_Files("tag_\d+",folder_name,"tag_1",count=0)
    
    
    
     #整理 MG 生成的 Events 文件夹
    def Tidy_MG_Events_Folder(self, path):
       #print("In Tidy_MG_Events_Folder, tidy the following Event folder", path)
       for sub_folder in Path(path).iterdir():
           com_name=os.path.basename(sub_folder).split("_",2)[0]
           if com_name != "run":
               continue
           num=int(sub_folder.name.split("_",2)[1])
           format_num=str(num).rjust(2,"0")
           #print("In Tidy_MG_Events_Folder, tidy sub folder", sub_folder)
           self.Tidy_MG_Run_Folder(sub_folder,format_num)




# 将MG生成的文件从original_folder转移到一个新的文件夹target_folder中，并对run_0x子文件夹重命名为接续着之前的序号
    def Move_MG_Event(self, original_folder,target_folder=""):
        if original_folder == target_folder:
            return(original_folder)
        file_name_list=[]
        self.Tidy_MG_Events_Folder(original_folder)
        ori_maxnum=len(Find_File(target_folder,"run","folder"))
        #files=Sort_Files_by_Time(target_folder)
        name_list=[]
        for sub_folder in sorted(Path(original_folder).iterdir()):
            #print(sub_folder, ori_maxnum, target_folder)
            if not sub_folder.is_dir():
                continue
            #生成新文件夹序号，应为原有文件夹序号+1
            sub_folder_name=os.path.basename(sub_folder)
            ori_maxnum=ori_maxnum+1
            new_num=str(ori_maxnum).rjust(2,"0")
            Tidy_MG_Run_Folder(sub_folder,new_num)
            #
            #生成新的文件夹名称，序号正好接着原有文件夹名
            if target_folder != "":
                com_name=os.path.basename(sub_folder).split("_",2)[0]   #取sub_folder基文件并且以'_'分割
                new_name=os.path.join(target_folder,com_name+"_"+new_num)   
                name_list.append(Path(new_name))
                if sub_folder != new_name:
                    print(sub_folder,new_name)
                    Move_File(sub_folder, new_name)    #将sub_folder文件移动到new_name中
            else:
                name_list.append(Path(str(sub_folder)))
        #复制文件夹
            Copy_File(sub_folder, new_name)
            print("In Move_MG_Event: copy", sub_folder, " to ", new_name)
        return(name_list)

# 返回用于存储的每次不同参数生成的事例文件的文件名，文件名构成一个列表，每个文件对应一个参数点。
# 每个文件中的内容为该参数下生成的所有事例文件名
    def Move_MG_Event_MultiRun_for_one_BP(self, original_folder="",target_folder=""):
        if original_folder=="":
            original_folder=self.MG_Dir["event_stored_folder"]
        if target_folder=="":
            target_folder=self.MG_Dir["event_stored_folder"]
        #print("original_folder",self.MG_Dir["original_folder"])
        #print("target_folder",target_folder)
        out_files=[]
        for sub_folder in sorted(Path(original_folder).iterdir()):
            new_folder_name=Get_File_Name(sub_folder)
            folder_num=new_folder_name.split("_")[-1]   #取sub_folder基文件并且以'_'分割
            if folder_num == "0":
                continue
            event_folder=Path(os.path.join(sub_folder,"Events"))
            if target_folder != "":
                target_sub_folder=target_folder / new_folder_name / "Events"
                Create_Folder(target_sub_folder,"/")
                new_files=self.Move_MG_Event(event_folder,target_sub_folder)
                out_file=target_sub_folder / (new_folder_name+"_moved_event_files.dat")
                out_files.append(out_file)
            else:
                new_files=Move_MG_Event(event_folder,target_folder)
                out_file=original_folder / new_folder_name / "delphes_event_files.dat"
                out_files.append(out_file)
                print(out_file)
            f=open(out_file,'w')   #‘只写’模式打开out_file
            for file in new_files.iterdir():
                if file.is_file():
                    continue
                write_file_name=file / "tag_1_delphes_events.root"
                f.write(str(write_file_name))
                f.write("\n")
            f.close()
            #print("In Move_MG_Event_MultiRun_for_one_BP: new_folder_name ", new_folder_name, " new_files ", new_files)
            self.MG_Dir["multi_event_files"]=out_files
            #print("multi_event_files",self.MG_Dir["multi_event_files"])
        return(out_files)




    def Multi_Event_Print(self):
        if "multi_event_files" in self.MG_Dir:
            files=self.MG_Dir["multi_event_files"]
            print("	The multi event files Param is : ")
            print("		file_name: ", files)




#######################################################################################
###################################### 如果文件已经生成好 收集截面数据#################
#######################################################################################


    # 从自动Scan生成的MG文件夹中，抽取 every generation event number 参数
    def Extract_Scan_Generated_Event_Number(self, target_folder_name):
        numbers= []
        for this_file in Path(target_folder_name).iterdir():
            #file_name = os.path.join(target_folder_name.name ,this_file.name)
            file_kind=this_file.suffix
            if file_kind == ".root":
                number = ROOT_Get_AllEntries_Number(this_file)
                numbers.append(number)
            #elif file_kind == ".gz":
                #events = pylhe.read_lhe_with_attributes(this_file)
                #print("extract number from gz")
                #number = pylhe.read_num_events(this_file)
                #numbers.append(number)
                #print("gz number",number, this_file)
        return(numbers)


    # 从自动Scan生成的MG文件夹中，抽取scan参数（因为MG偶尔会中途崩溃，所以不生成总结的scan文件）
    def Extract_Scan_Xection(self, folder_name,output_general_parafile):
        each_event_folder=folder_name/"Events/"
        #print("In Extract_Scan_Xection: now extract info in ", each_event_folder)
        para_in_one_node=[]
        #print("output general_file",output_general_parafile)
        #print("folder_name",folder_name.name)
        output_parafile=str(output_general_parafile).format(folder_name.name)
        #print("output_parafile",output_parafile)
        folder_list=Sort_Files_by_Name(os.listdir(each_event_folder))
        if not self._process["MG_lhe_event_exist"] and not self._process["MG_hepmc_event_exist"] and not self._process["MG_delphes_event_exist"] :
            # 如果事例文件均存在
            return(para_in_one_node)
        #for run_folder in Path(each_event_folder).iterdir():
        for run_folder in folder_list:
            one_para={}
            one_para["#run_folder"]=each_event_folder/run_folder
            if not Path(one_para["#run_folder"]).is_dir():
                continue
            label="#  Integrated weight (pb)  :"
            # default set only one file (run_xx_tag_file.dat) has the label in each folder 
            #xection_word_list=Extract_One_Sentence_From_MultiFile(one_para["#run_folder"],label)   #查找文件名
            file_list, word_list, delphes_list=Extract_One_Sentence_From_MultiFile(one_para["#run_folder"],label)   #查找文件名
            one_para["#run_name"] = one_para["#run_folder"]/delphes_list[0]
            cross=[word.split(":",2)[1] for word in word_list] 
            #log_file=xection_word_list[0][0]
            log_file=file_list[0]
            word_list, input_line_list = Find_Line(log_file, self.MG_Setting["label_value"])#找到行的位置并往下进行替换
            for sentence in word_list:
                split_sentence=list(filter(lambda x : x, sentence.split(" ")))
                value=split_sentence[1]
                para_name=split_sentence[-1].replace("\n","")
                para_name_tmp=split_sentence[-2].replace("\n","")
                if(para_name == "" ):
                    para_name=para_name_tmp
                    value=split_sentence[2]
                if (para_name == "tb"):
                    para_name="tb"
                elif (para_name == "TB"):
                    para_name="tb"
                elif (para_name == "sinbma"):
                    para_name="sba"
                elif (para_name == "cba"):
                    para_name="cba"
                elif (para_name == "mh1"):
                    para_name="mh"
                elif (para_name == "mhl"):
                    para_name="mh"
                elif (para_name == "mh2"):
                    para_name="mH"
                elif (para_name == "mhh"):
                    para_name="mH"
                elif (para_name == "mh3"):
                    para_name="mA"
                elif (para_name == "mha"):
                    para_name="mA"
                elif (para_name == "mhc"):
                    para_name="mch"
                elif (para_name == "mhp"):
                    para_name="mch"
                elif (para_name == "m122"):
                    para_name="m12_2"
                elif (para_name == "whl"):
                    para_name="wh"
                elif (para_name == "Whh"):
                    para_name="wH"
                elif (para_name == "Wha"):
                    para_name="wA"
                elif (para_name == "Whp"):
                    para_name="wch"
                elif (para_name == "Whl"):
                    para_name="wch"
                one_para[para_name]=value
            #print("one_para",one_para)
            one_para["cross"]=float(cross[0])*2000 #转换为fb， 且包含 ++， -- 位形  
            self.cut_xection.append(float(cross[0])*2000) #转换为 fb
            if self._process["MG_lhe_event_exist"] or self._process["MG_delphes_event_exist"]:
                number_list=self.Extract_Scan_Generated_Event_Number(one_para["#run_folder"])
                one_para["EventNo"]=number_list[0]

            para_in_one_node.append(one_para)
        Write_List_by_DF_to_File(para_in_one_node,output_parafile)   #写入到.csv输出文件
        return(para_in_one_node, each_event_folder, output_parafile)



    # 从 MG 中生成的Event文件里，利用Extract_Scan_Xection提取cross section数据，并组合成 scan 的参数文件。
    def Extract_MultiXection_from_Folder(self, input_folders, output_general_file):
        #input_folders = self.MG_Dir["split_event_folder"]
        #output_general_file = self.MG_Dir["xection_general_file_name"]
        print("Extract scan param from MG run folder", input_folders)
        #print("Extract scan param from MG run folder", output_general_file)
        all_cross=[]
        para_output_folders=[]
        input_event_folders=[]
        #print("The scaned param file number is ",len(input_folders))
        for sub_folder in input_folders:
            # _ion means in one node
            output_xection_para, input_event_sub_folder, para_output_file=self.Extract_Scan_Xection(sub_folder,output_general_file) 
            all_cross.append(output_xection_para)
            input_event_folders.append(input_event_sub_folder)
            para_output_folders.append(para_output_file)
        return(all_cross, para_output_folders, input_event_folders)


    # 比较上面提取出的参数文件与想要处理的参数文件中有何不同， 并将缺乏的参数bp点输出 （因为MG有时报错不能完全执行。）
    def Dataframe_One_with_Multi_Param_Files(self, one_input_file, multi_input_files, para_name):
        print("Load origin param, one_input_file", one_input_file)
        print("Load origin param, para_name", para_name)
        origin_df=Load_THDM_Param(one_input_file,para_name)#读取para_name中的one_input_file
        #print("origin_df", origin_df)

        # 从MG文件中提取的参数已经被放入输出文件夹中，现在将需要的参数那几列提取出来。
        print("Load scaned param",multi_input_files)
        generated_df=[]
        for this_file in multi_input_files:
            #print("file_name",this_file)
            df_tmp = Load_THDM_Param(this_file,para_name)
            #print("df_tmp", df_tmp)
            generated_df.append(df_tmp)
        #print("generated_df",generated_df, len(generated_df))
        return(origin_df, generated_df)



    # 将两组文件相比较，并输出不同之处 
    def Compare_One_with_Multi_Param_DF(self, one_input_df, multi_input_df):
        print("In Compare_One_with_Multi_Param_DF, Compare origin param file and extract param file")
        print("In Compare_One_with_Multi_Param_DF, the input one df is ", one_input_df)
        print("In Compare_One_with_Multi_Param_DF, the input multi df is ", multi_input_df)
        Judge_different=False
        differents=[]
        current_length=0
        for index_df, this_df in enumerate(multi_input_df):
            begin_num=current_length
            current_length=current_length+len(this_df)
            end_num=current_length
            print("In Compare_One_with_Multi_Param_DF "," the selected rows are from", begin_num, " to ", end_num)
            split_df=one_input_df[begin_num:end_num]
            split_df=split_df.reset_index(drop=True)   #重置索引(重新定义行数和列数,都从0开始),drop=True:不想保留原来的index 
            #different_part=this_df.compare(split_df)   #compare()与this_df比较并显示差异
            #print("this_df",this_df)
            #print("split_df",split_df)
            different_part=datacompy.Compare(this_df,split_df,abs_tol=0.01,join_columns=['mH'])
            if not different_part.matches():
                #if not different_part.empty:
                Judge_different=True
                print("The different part is in ", index_df+1)
                print("The different content is ", different_part)
                differents.append(different_part)
        return(Judge_different,differents)


    # 合并几个参数在一起
    # 将整理出的参数文件放入 MG 对应的文件夹中
    def Pack_Scan_Param(self, combined_file, output_folder):
        generated_df = []
        columns=""
        for this_file in output_folder:
            df_tmp = Load_THDM_Param(this_file)
            #print("file_name",this_file)
            #print("df_tmp", df_tmp)
            average_cross = df_tmp["cross"].mean()
            run_file_list = df_tmp["#run_name"].to_list()
            total_event_num = df_tmp["EventNo"].sum()
            df_tmp["FileNo"] = len(df_tmp)
            columns=df_tmp.columns
            new_row = df_tmp.loc[0].copy()
            new_row["cross"] = average_cross
            new_row["#run_name"] = run_file_list
            new_row["EventNo"] = total_event_num 
            #new_row["FileNo"] = len(df_tmp) 
            #print("new_row",new_row)
            generated_df.append(new_row.to_list())

        #combined_df=pd.concat(generated_df, axis=0, ignore_index=True)
        combined_df = pd.DataFrame(generated_df)
        #print("generated df",generated_df)
        combined_df=combined_df.reset_index(drop=True)
        combined_df.columns=columns
        #print("combined df",combined_df)
        #this_combined_file=str(combined_file).format(fnum=len(combined_df))
        this_combined_file=self.MG_Dir["cut_file_name"]
        combined_df.to_csv(this_combined_file)
        print("The combined scan para files are in ", this_combined_file)
        return(this_combined_file)


    # 将上述函数整合在一起， 读取并整理scan的参数结果
    def Collect_MG_Cross(self):
        split_event_folder = self.MG_Dir["split_event_folder"]
        combined_file = self.MG_Dir["combined_scan_file"]
        output_general_file = self.MG_Dir["xection_general_file_name"]
        original_parafile = self._process["theoretical"]
        para_name = Get_Maplist_Key(self.MG_Setting["replace_value"])
        Create_Folder_from_FileDir(combined_file,"/")
        # 从MG中生成的split_event_folder，利用Extract_Scan_Xection提取cross section数据，并输出文件为output_general_file(带有scan参数的)。
        all_cross, para_output_folder, input_data_folder=self.Extract_MultiXection_from_Folder(self.MG_Dir["split_event_folder"], output_general_file) 
        #print("In Collect_MG_Cross, the all_cross is ", all_cross)
        for cross_i, cross_info in enumerate (all_cross):
            print("In ",cross_i, "-th event, run number is ", len(cross_info))
        #print("In Collect_MG_Cross, the para_output_folder is ", para_output_folder)
        #print("In Collect_MG_Cross, the input_data_folder is ", input_data_folder)
        #将以上函数提取出来的数据列表(只列出para_name)
        #检查参数是否与原参数一致
        #origin_df, generated_df=self.Dataframe_One_with_Multi_Param_Files(original_parafile, para_output_folder, para_name)    
        #Judge_different, differents=self.Compare_One_with_Multi_Param_DF(origin_df, generated_df)  #比较参数文件的不同之处，并输出未run的Bp点
        #print("Two param files are different, still have some BPs are not generated, please check:",output_general_file)
        #if not Judge_different :
        #    print("Two param files are different, still have some BPs are not generated, please check:",output_general_parafile)
        self.Pack_Scan_Param(combined_file, para_output_folder) #合并参数文件
        #Copy_File(str(combined_file).format(fnum=len(origin_df)),str(output_general_file).format("total"))
        Copy_File(str(self.MG_Dir["cut_file_name"]),str(output_general_file).format("total"))
        print(self.MG_Dir["cut_file_name"])
        return(all_cross, para_output_folder, input_data_folder)



#######################################################################################
################################### 如果直接得到的结果不准确 ##########################
#######################################################################################

    def Cal_Parton_Cut_Xection(self):
        #生成MG对应的加parton_cut
        #cut_mg5 = pd.read_table(self.MG_Dir["cut_file_name"], delim_whitespace=True)    #读取.txt文件
        cut_mg5 = pd.read_table(self.MG_Dir["cut_file_name"], sep="\s+")    #读取.txt文件
        if len(cut_mg5.columns)==1:
            cut_mg5 = pd.read_table(self.MG_Dir["cut_file_name"], sep=",")    #读取.txt文件

        self.cut_xection=cut_mg5["cross"]

    def Cal_Parton_Cut_Xection_with_nocut(self):
        #生成MG对应的加parton_cut
        cut_mg5 = pd.read_table(self.MG_Dir["cut_file_name"], delim_whitespace=True)    #读取.txt文件
        if len(cut_mg5.columns)==1:
            cut_mg5 = pd.read_table(self.MG_Dir["cut_file_name"], sep=",")    #读取.txt文件

        cut_xection=cut_mg5["cross"]

        nocut_mg5 = pd.read_table(self.MG_Dir["nocut_file_name"], delim_whitespace=True)
        if len(nocut_mg5.columns)==1:
            nocut_mg5 = pd.read_table(self.MG_Dir["nocut_file_name"], sep=",")
        no_cut_xection=nocut_mg5["cross"]

        df_theo = pd.read_table(self._process["theoretical"])
        no_cut_theoretical=df_theo["xsh_W4b"]*0.2134

        cut_cross=[round(xx,2) for xx in np.multiply(cut_xection,no_cut_theoretical)/no_cut_xection]   #np.multiply()数组和矩阵对应位置相乘，输出与相乘数组/矩阵的大小一致
        self.MG_Results["cross"]=cut_cross
        return(cut_cross)


#######################################################################################
################################# 提取最终结果并对最终结果画图 ########################
#######################################################################################

    # 收集MG结果，并画出热力图
    def Results(self):
        #print("In ARCH:, the general MG results are stored in ", self.MG_Dir["output_tmp_file"])
        cut_xection = self.Cal_Parton_Cut_Xection()

        Generate_Hotmap_Data_from_Para_and_Value(self._process["theoretical"], self._process["plot"]["df_para"], self.MG_Results["cross"], self.MG_Dir["hotmap_dat_file"], self.MG_Setting["plot"]["var_name"])
        Generate_Hotmap_Code(self.MG_Setting["plot"], self._param_dir["hotmap_template"])





